#include "vxhandcontroller.h"
#include "Vx.h"
#include "vxmousetransmitter.h"
#include "vxcommandscontroller.h"


class SceneDragTransition : public QSignalTransition
{
	Q_OBJECT
public:
	SceneDragTransition(VxHandController * controller, QState * beginDragState) :
			QSignalTransition::QSignalTransition(VxMouseTransmitter::instance(),
								SIGNAL(mousePressedMove(QPoint))),
			_controller(controller), _scenePoint(NULL)

	{
		connect(beginDragState, SIGNAL(entered()), this, SLOT(_beginDrag()));
	}

	void onTransition(QEvent *event)
	{
		if (event->type() != QEvent::StateMachineSignal){
			return;
		}

		QStateMachine::SignalEvent * signal = static_cast<QStateMachine::SignalEvent *>(event);

		QPoint globalPos = signal->arguments().first().toPoint();

		QGraphicsView * view = _controller->view();

		if (_scenePoint == NULL){
			QPointF p = view->mapToScene(view->mapFromGlobal(globalPos));
			_scenePoint = new QPointF(p.x(), p.y());
		} else {
			QPointF p = view->mapToScene(view->mapFromGlobal(globalPos));

			qreal dx = _scenePoint->x() - p.x();
			qreal dy = _scenePoint->y() - p.y();

			QPointF center = Vx::viewPoint(view);

			_controller->setViewPoint(QPointF(center.x() + dx, center.y() + dy));

			//
			qreal dlt = sqrt(dx*dx + dy*dy);

			view->setProperty("_delta", QVariant::fromValue(dlt));
			view->setProperty("_deltax", QVariant::fromValue(dx));
			view->setProperty("_deltay", QVariant::fromValue(dy));

		}
	}

private:
	VxHandController * _controller;
	QPointF * _scenePoint;


private slots:
	void _beginDrag()
	{
		delete _scenePoint;
		_scenePoint = NULL;
	}

};


VxHandController::VxHandController(QGraphicsView * view) :
	_view(view)
{

	_buildStateMachine();

	connect(VxCommandsController::instance(_view), SIGNAL(cancelAnimation()), this, SLOT(cancelAnimation()));
	connect(VxMouseTransmitter::instance(), SIGNAL(mousePressedIdle()), this, SLOT(_cancelMomentum()));

	_animation = new QPropertyAnimation(this, "viewPoint", this);
	_animation->setEasingCurve(QEasingCurve::OutQuart);

	connect(VxCommandsController::instance(_view), SIGNAL(beginHandScroll()), this, SLOT(_beginHandsController()));
	connect(VxCommandsController::instance(_view), SIGNAL(endHandScroll()), this, SLOT(_endHandsController()));
	connect(VxCommandsController::instance(_view), SIGNAL(endHandScroll()), this, SLOT(cancelAnimation()));

	//_indicator = _view->scene()->addEllipse(0,0,5,5, QPen(QColor(0,0,222)),QBrush(QColor(0,222,22)));

}

void VxHandController::_beginHandsController()
{
	_view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
}

void VxHandController::_endHandsController()
{
	_view->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
}



void VxHandController::_buildStateMachine()
{
	QStateMachine * machine = new QStateMachine(this);
	QState * stateReleased = new QState(machine);
	QState * stateSpacePressed = new QState(machine);
	QState * stateMousePressed = new QState(machine);

	VxCommandsController * commands = VxCommandsController::instance(_view);

	// released -> space pressed

	QSignalTransition * releasedToBegin = new QSignalTransition(commands, SIGNAL(beginHandScroll()));
	releasedToBegin->setTargetState(stateSpacePressed);
	stateReleased->addTransition(releasedToBegin);

	// released <- space pressed
	QSignalTransition * beginnedToReleased = new QSignalTransition(commands, SIGNAL(endHandScroll()));
	beginnedToReleased->setTargetState(stateReleased);
	stateSpacePressed->addTransition(beginnedToReleased);

	QSignalTransition * mtransSpacePressedToReleased =
			new QSignalTransition(VxMouseTransmitter::instance(), SIGNAL(mouseReleased(QMouseEvent*)));

	mtransSpacePressedToReleased->setTargetState(stateReleased);
	stateSpacePressed->addTransition(mtransSpacePressedToReleased);

	//             space pressed -> mouse button pressed
	QSignalTransition * transMousePressed =
			new QSignalTransition(VxMouseTransmitter::instance(), SIGNAL(mousePressed(QMouseEvent*)));
	transMousePressed->setTargetState(stateMousePressed);
	stateSpacePressed->addTransition(transMousePressed);


	//								mouse button pressed <= mouse move (drag scene) =>
	SceneDragTransition * transSceneDrag = new SceneDragTransition(this, stateMousePressed);
	stateMousePressed->addTransition(transSceneDrag);


	// released <-	-	-	-	-	mouse button pressed
	QSignalTransition * mtransMousePressedToPressed =
			new QSignalTransition(VxMouseTransmitter::instance(), SIGNAL(mouseReleased(QMouseEvent*)));
	mtransMousePressedToPressed->setTargetState(stateMousePressed);
	stateMousePressed->addTransition(mtransMousePressedToPressed);

	QSignalTransition * mousePressedToReleased = new QSignalTransition(commands, SIGNAL(endHandScroll()));

	mousePressedToReleased->setTargetState(stateReleased);
	stateMousePressed->addTransition(mousePressedToReleased);

	machine->setInitialState(stateReleased);
	machine->start();


	connect(stateMousePressed, SIGNAL(exited()), this, SLOT(_mouseDragFinished()));

	connect(VxMouseTransmitter::instance(), SIGNAL(mousePressed(QMouseEvent*)), this, SLOT(cancelAnimation()));

}


void VxHandController::setViewPoint(QPointF point)
{
	_view->centerOn(point);
}


QPointF VxHandController::_getViewPoint()
{
	return Vx::viewPoint(_view);
}


QPointF VxHandController::validateEndPoint(QPointF point)
{
	return point;
}



void VxHandController::_mouseDragFinished()
{
	qreal delta = _view->property("_delta").toReal();

	if (delta < 3){
		setViewPoint(validateEndPoint(Vx::viewPoint(_view)));
		return;
	}

	qreal deltax = _view->property("_deltax").toReal();
	qreal deltay = _view->property("_deltay").toReal();

	_view->setProperty("_delta", 0);

	QPointF center = Vx::viewPoint(_view);
	QPointF endpnt = validateEndPoint(QPointF(center.x() + deltax*3, center.y()+deltay*3));


	_animation->stop();
	_animation->setStartValue(center);
	_animation->setEndValue(endpnt);
	_animation->setDuration((Vx::HandMoveDelay > delta*3) ? Vx::HandMoveDelay : delta*3);
	_animation->start();

}


void VxHandController::cancelAnimation()
{
	_animation->stop();
}


void VxHandController::_cancelMomentum()
{
	_view->setProperty("_delta", 0);
}



#include "vxhandcontroller.moc"




















